package com.learnyou.server.xingzuo.common.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;
import java.util.stream.Collectors;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    @ExceptionHandler(value = LearnyouBootException.class)
    @ResponseBody
    public ApiResult methodArgumentNotValidExceptionHandler(HttpServletRequest req, LearnyouBootException e){

        return ApiResult.error(e.getCode(), e.getMessage());
    }

    /**
     * 请求参数类型不匹配
     *
     * @param e
     * @return
     */
    @ExceptionHandler({TypeMismatchException.class})
    @ResponseBody
    public ApiResult typeMismatchExceptionHandler(TypeMismatchException e) {
        return ApiResult.error("参数类型不匹配,参数" + e.getPropertyName() + "类型应该为" + e.getRequiredType());
    }

    /**
     * 请求参数个数不匹配
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public ApiResult missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        return ApiResult.error("缺少必要参数,参数名称为" + e.getParameterName());
    }

    /**
     * 请求方式错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public ApiResult httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        return ApiResult.error("405","请求方式错误");
    }

    /**
     * 返回解析错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    @ResponseBody
    public ApiResult httpMediaTypeNotAcceptabledExceptionHandler(HttpMediaTypeNotAcceptableException e) {
        return ApiResult.error("406", "返回解析错误");
    }


    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ApiResult methodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e){
        // 从异常对象中拿到ObjectError对象
        // 然后提取错误提示信息进行返回
        return ApiResult.error(e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(",")));
    }

    /**
     * Violation 参数校验异常
     *
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public ApiResult constraintViolationExceptionHandler(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        return ApiResult.error(constraintViolations.stream().map(ConstraintViolation::getMessageTemplate).collect(Collectors.joining(",")));
    }


    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ApiResult exceptionHandler(HttpServletRequest req, Exception e){
        log.error("未知异常！原因是:",e);
        return ApiResult.error(e.getMessage());
    }
}
